package com.yushu.common.config;

import com.yushu.common.config.cache.ShiroCacheManager;
import com.yushu.common.config.session.ShiroSessionDAO;
import com.yushu.common.config.shiro.ShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author test
 * @CreateDate 2020-12-03 15:47:25
 */
@Configuration
public class ShiroConfig {

    @Autowired
    private ShiroCacheManager shiroCacheManager;

    /**
     * 配置自定义SessionDAO
     *
     * @return
     */
    @Bean
    public SessionDAO sessionDAO() {
        SessionDAO sessionDAO = new ShiroSessionDAO(shiroCacheManager);
        return sessionDAO;
    }

    /**
     * 配置会话管理器
     *
     * @return
     */
    @Bean
    public SessionManager sessionManager() {
        // WEB 环境非HttpSession 会话管理器
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // 注入 自定义的SessionDao
        sessionManager.setSessionDAO(sessionDAO());
        return sessionManager;
    }

    /**
     * 配置安全管理器
     *
     * @return
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 注入自定义Realm
        securityManager.setRealm(shiroRealm());
        // 注入缓存管理器
        securityManager.setCacheManager(shiroCacheManager);
        // 注入会话管理器
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }




    /**
     * 启用Shiro注解
     *
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        // 注入安全管理器
        advisor.setSecurityManager(securityManager());
        return advisor;
    }



    /**
     * Shiro Realm 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的
     *
     * @param cacheManager
     * @return
     */
    /**
     * 装配 自定义Realm
     *
     * @return
     */
    @Bean
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        //告诉realm,使用credentialsMatcher加密算法类来验证密文
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        shiroRealm.setCachingEnabled(false);
        return shiroRealm;
    }
    /**
     * 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     * ）
     * 可以扩展凭证匹配器，实现 输入密码错误次数后锁定等功能，下一次
     * @return
     */
    @Bean(name="credentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1);//散列的次数，比如散列两次，相当于 md5(md5(""));
        //storedCredentialsHexEncoded默认是true，此时用的是密码加密用的是Hex编码；false时用Base64编码
//        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);

        return hashedCredentialsMatcher;
    }


    /**
     * 配置权限权限过滤器
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
        // 注入安全管理器
        filter.setSecurityManager(securityManager());
        // 未认证的跳转地址
        filter.setLoginUrl("/");
        Map<String, String> chain = new LinkedHashMap<>();
        chain.put("/", "anon"); // 登录链接不拦截
//      chain.put("/login", "anon"); // 登录链接不拦截
//      chain.put("/toLogin", "anon"); // 登录链接不拦截
        chain.put("/sysLogin/captcha.jpg", "anon"); //验证码校验不拦截
        chain.put("/authority/pmUser/register", "anon"); //用户注册方法不拦截
        chain.put("/sysLogin/captcha", "anon"); //验证码校验不拦截
        chain.put("/sysLogin/toRegister", "anon"); //跳转注册页面不拦截
        chain.put("/sysLogin/toLogin", "anon"); //验证码校验不拦截
        chain.put("/sysLogin/logout", "anon"); //验证码校验不拦截
        chain.put("/sysLogin/login", "anon"); //验证码校验不拦截
        chain.put("/authority/pmUser/validateCode","anon");//邮箱验证码不拦截
        chain.put("/authority/pmUser/validateUserName", "anon"); //用户名是否唯一
        chain.put("/authority/pmUser/validateEmail", "anon"); //用户名是否唯一
        chain.put("/authority/pmUser/save", "anon"); //用户名是否唯一
        chain.put("/swagger-ui.html", "anon"); //用户名是否唯一
        chain.put("/v2/api-docs", "anon"); //用户名是否唯一
        chain.put("/sysLogin/toForgetPass", "anon"); //跳转忘记密码页面不拦截
        chain.put("/authority/pmUser/validateQueryEmail","anon");//校验邮箱方法不拦截
        chain.put("/authority/pmUser/changeForgetPassword","anon");//忘记密码方法不拦截
        chain.put("/assets/**", "anon");
        chain.put("/inspinia/**", "anon");
        chain.put("/**", "authc");


        filter.setFilterChainDefinitionMap(chain);
        return filter;
    }


}




















